using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace EnhancedTextBox
{
    /// <summary>
    /// A text box with added hints feature.
    /// </summary>
    public partial class EnhancedTextBox : TextBox
    {
        /// <summary>
        /// Gets/Sets the array of words to be proposed for the user.
        /// </summary>
        [Description("These words will be proposed to the user.")]
        public string[] Words { get; set; }

        /// <summary>
        /// Gets/Sets the array of words' descriptons.
        /// </summary>
        [Description("These are descriptions for proposed words.")]
        public string[] Descriptions { get; set; }

        /// <summary>
        /// Gets/Sets list of words separators.
        /// </summary>
        [Description("These will split entered string into words.")]
        public char[] Separators { get; set; }

        /// <summary>
        /// Gets/Sets how many words can be visible at one time.
        /// </summary>
        [Description("Maximum numvber of visible words.")]
        public int VisibleItemsCount
        {
            get { return form.MaximumVisibleWords; }
            set { form.MaximumVisibleWords = value; }
        }

        /// <summary>
        /// Gets/Sets font of proposed text.
        /// </summary>
        [Description("Proposal text font.")]
	    public Font TextFont
	    {
            get { return form.Font; }
            set { form.Font = value; }
	    }

        /// <summary>
        /// Gets/Sets top background color.
        /// </summary>
        [Description("Top background color.")]
        public Color TopColor { get; set; }

        /// <summary>
        /// Gets/Sets bottom background color.
        /// </summary>
        [Description("Bottom background color.")]
        public Color BottomColor { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        public EnhancedTextBox()
        {
            InitializeComponent();

            TopColor = Color.FromArgb(255, 255, 255);
            BottomColor = Color.FromArgb(220, 220, 220);

            Leave += NewLeavehandler;
        }

        readonly FloatingForm form = new FloatingForm();

        protected override void OnKeyDown(KeyEventArgs args)
        {
            if ( form.Visible && ( args.KeyCode == Keys.Down || args.KeyCode == Keys.Up || args.KeyCode == Keys.Escape ))
            {
                args.SuppressKeyPress = true;
            }

            base.OnKeyDown(args);
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            EnhancedKeyUpHandler(this, e);
            base.OnKeyDown(e);
        }

        private void EnhancedKeyUpHandler(object sender, KeyEventArgs args)
        {
            if (Environment.OSVersion.Platform != PlatformID.Win32NT) return;
            
            if (Words == null)
            {
                return;
            }

            Update(Text);

            if (form.Visible && args.KeyCode == Keys.Down)
            {
                form.SelectedIndex += 1;
                args.SuppressKeyPress = true;
            }

            if (form.Visible && args.KeyCode == Keys.Up)
            {
                form.SelectedIndex -= 1;
                args.SuppressKeyPress = true;
            }

            if (form.Visible && args.KeyCode == Keys.Escape)
            {
                form.Items.Clear();
                args.SuppressKeyPress = true;
            }

            if (form.Visible && args.KeyCode == Keys.Return)
            {
                string selected = form.Items[form.SelectedIndex];
                Text = Text.Remove(Text.Length - lastPart.Length);
                Text = Text.Insert(Text.Length, selected);
                SelectionStart = Text.Length;
                Update(Text);
                form.SelectedIndex = 0;
            }

            form.Location = Parent.PointToScreen(new Point(Left, Bottom));
            form.Width = Width;

            if (form.Items.Count > 0)
            {
                form.Visible = true;
                form.Refresh();
            }
            else
            {
                form.Visible = false;
            }
        }

        private void NewLeavehandler(object sender, EventArgs args)
        {
            form.Hide();
        }

        private string lastPart;

        private void Update(string typedText)
        {
            if (Separators == null)
            {
                return;
            }
            
            form.Items.Clear();
            form.Descriptions.Clear();

            int l = 0;

            foreach (String str in Words)
            {
                String [] parts = typedText.Split(Separators);

                lastPart = parts[parts.Length - 1];

                if ( lastPart.Length > 0 && str.StartsWith(lastPart) )
                {
                    form.Items.Add(str);
                    form.Descriptions.Add(Descriptions[l]);
                }

                l++;
            }

            if ( form.SelectedIndex > form.Items.Count - 1)
            {
                form.SelectedIndex = 0;
            }

            form.Height = 2 + Math.Min(form.MaximumVisibleWords, form.Items.Count) * (form.Font.Height+6);

        }
    }
}
